#pragma once
#include <vector>
#include <string>
#include <list>
#include <sstream>
#include <memory>
#include <fstream>
#include <alg/amcutilityalgdataanalysis.h>
#include <alg/amcutilityalgfft.h>

#include <cmd/common.h>
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <data/mqtt.h>
#include <data/rabbitmq.h>

namespace capture{
	const std::string configHeaderNames[] = {
		"序号",         "参数名称",     "所属系统",     "参数类型",     "数据类型",
		"范围下限",     "范围上限",     "起始字节",     "起始位",       "长度",	
		"物理量还原方式","物理量还原LSB","物理量还原偏置", "数学量还原方式","数学量还原LSB",
		"数学量还原偏置","单位",        "物理量显示",   "权限",         "精度",	
		"初始值",		"备注",
	};

	enum EParamType{
		PT_CONTINUOUS = 0,	// 连续量
		PT_DISCRETE = 1,	// 离散量
	};
	// 数据类型
	enum EDataType{
		DT_POSITIVE = 0, // 正数范围
		DT_NEGATIVE = 1, // 负数范围
	};
	enum EDecodeType{
		DT_PHY=1,
		DT_MATH,
		DT_PHY_MATH,
	};
	// 物理量还原方式
	enum EPhyReduceType{
		PRT_MULTIPLY = 0,	// 乘以LSB加偏移
		PRT_DEVIDE = 1,		// LSB除以原码
		PRT_TABLE = 2,		// 查T4表
		PRT_AS_FLOAT = 3,	// 按照浮点解算
	};
	// 数学量还原方式
	enum EMathReduceType{
		MRT_MULTIPLY = 0,	// 乘以LSB加偏移
		MRT_DEVIDE = 1,		// LSB除以数字量原码值
	};
		// 物理量显示方式
	enum EPhyShowType{
		PST_DIRECT, // 直接显示
		PST_HMS,	// 时分秒显示
		PST_DMS,	// 度分秒显示
	};
	std::map<int,std::map<int,std::map<int,std::map<std::string,std::string>>>> calibrate;
	void read_config(int id, int board, int index,std::string filename){
		std::stringstream sconfig;
		std::ifstream ifs(filename);
		if(ifs.is_open()){
			ifs>>sconfig.rdbuf();
			std::vector<std::string> rows;
			boost::algorithm::split(rows,sconfig.str(),boost::is_any_of("\n"));
			std::vector<std::string> header;
			boost::algorithm::split(header,rows[0].c_str(),boost::is_any_of("\t"));
			for(int i=1;i<rows.size();++i){
				std::vector<std::string> cols;
				boost::algorithm::split(cols,rows[i].c_str(),boost::is_any_of("\t"));
				for(int j=1;j<cols.size();++j){
					int channel=0,card=0;
					if(cols[1].find("通道")!=cols[1].npos)
						channel = atoi(cols[1].substr(cols[1].find("通道")+strlen("通道")).c_str())-1;
					if(cols[2].find("板卡")!=cols[2].npos)
						card = atoi(cols[2].substr(cols[2].find("板卡")+strlen("板卡")).c_str());
					else
						card = atoi(cols[1].substr(cols[1].find("板卡")+strlen("板卡")).c_str());

					if(index==card)
						calibrate[id][board][channel][header[j]]=cols[j];
				}
			}
			ifs.close();
		}
	}
	double calibrate_data(double origin, int id, int board, int channelid, EDecodeType method){
		double value = 0;
		auto mp = calibrate[id][board][channelid];
		switch(method){
			case DT_PHY_MATH:
			case DT_PHY:{
				switch(atoi(mp[configHeaderNames[10]].c_str())){
					case PRT_MULTIPLY:value = origin*atof(mp[configHeaderNames[11]].c_str())+atof(mp[configHeaderNames[12]].c_str());break;
					case PRT_DEVIDE:value = atof(mp[configHeaderNames[11]].c_str())/origin;break;
					case PRT_TABLE:break;
					case PRT_AS_FLOAT:value = *(float*)&(*(int*)&origin);break;
					default:
						BOOST_LOG_TRIVIAL(error)<<"calibrate data type error:"<<mp[configHeaderNames[10]];
						return 0.0;
				}
				if(method==DT_PHY_MATH){
					origin = value;
				}else{
					break;
				}
			}
			case DT_MATH:{
				switch(atoi(mp[configHeaderNames[13]].c_str())){
					case MRT_MULTIPLY:value = origin*atof(mp[configHeaderNames[14]].c_str())+atof(mp[configHeaderNames[15]].c_str());break;
					case MRT_DEVIDE:value = atof(mp[configHeaderNames[14]].c_str())/origin;break;
					default:
						BOOST_LOG_TRIVIAL(error)<<"calibrate data type error:"<<mp[configHeaderNames[13]];
						return 0.0;
				}
			}
		}
		return value-atof(mp[configHeaderNames[20]].c_str());
	}
	void feature(const std::vector<unsigned char>& data,int id,int board, std::map<int,std::vector<double>>& cache){
		switch(id){
			case 0x7376:{
				for(int i=0,j=0;i<data.size();i+=4,j=++j%6){
					cache[j].emplace_back(calibrate_data(*(float*)&data[i],id,board,j,DT_PHY_MATH));
				}
				break;
			}
			case 0x7377:{
				for(int i=0,j=0;i<data.size();i+=4,j=++j%16){
					cache[j].emplace_back(calibrate_data(*(float*)&data[i],id,board,j,DT_PHY_MATH));
				}
				break;
			}
			case 0x7511:{
				for(int i=0;i<data.size()*32;++i){
					cache[i].emplace_back(data[i/32]>>(i%32)&0x1);
				}
				break;
			}
			default:break;
		}
	}
	std::string JSON2String(const Json::Value& j){
		Json::FastWriter writer;
		return writer.write(j);	
	}
	Json::Value pack_feature(double data,std::string check_point_id,std::string check_point_name,
		std::string measure_point_id,std::string measure_point_desc="",std::string measure_point_unit=""){
		Json::Value json_ret;
		json_ret["data"]=std::to_string(data);

		std::stringstream ss;
		auto now = std::chrono::system_clock::now();
	    std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
    	std::tm* now_tm = std::localtime(&now_time_t);
		auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
		ss << std::put_time(now_tm, "%Y-%m-%d %H:%M:%S")<< "." << std::setfill('0') << std::setw(3) << ms.count();

		json_ret["up_time"]=ss.str();
		json_ret["check_point_id"]=check_point_id;
		json_ret["check_point_name"]=check_point_name;
		json_ret["measure_point_id"]=measure_point_id;
		json_ret["measure_point_desc"]=measure_point_desc;
		json_ret["measure_point_unit"]=measure_point_unit;
		return json_ret;
	}
	template <std::size_t... Is>
	void calc_feature(std::string topic,std::vector<double>& data,
		std::vector<std::pair<std::function<int(double*,int,double*)>,std::initializer_list<std::string>>> proc
		, std::index_sequence<Is...>){
		if(data.size()>0){
			for(auto it:proc){
				double d_data=0;
				auto func = std::get<0>(it);
				auto args = std::get<1>(it);
				func(&data[0],(int)data.size(),&d_data);
				std::string msg = JSON2String(pack_feature(d_data,args.begin()[Is]...));
				mqttplus::inst()->publish(topic, msg);
				rabbitmqplus::inst()->publish(topic, msg);
			}
		}
	}
	void send_feature_data(int id,int board,const std::map<int, std::vector<double>>& data, std::string check_point_id,std::string check_point_name){
		for(auto it : data){
			if(id==0x7376&&it.second.size()){
				std::transform(it.second.begin(), it.second.end(), it.second.begin(), [](double x) { return abs(x); });
				if(board==0){
					switch(it.first){
						case 0:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"DJ1SRDZD_101_arv","电机1输入端振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"DJ1SRDZD_101_std","电机1输入端振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"DJ1SRDZD_101_rms","电机1输入端振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 1:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"DJ1SCDZD_102_arv","电机1输出端振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"DJ1SCDZD_102_std","电机1输出端振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"DJ1SCDZD_102_rms","电机1输出端振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 2:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZQDXT1JCZD_103_arv","主驱动系统1基础振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZQDXT1JCZD_103_std","主驱动系统1基础振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"ZQDXT1JCZD_103_rms","主驱动系统1基础振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						default:break;
					}
				}else if(board==1){
					switch(it.first){
						case 0:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"JSX1ZD1_201_arv","减速箱1振动1整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"JSX1ZD1_201_std","减速箱1振动1标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"JSX1ZD1_201_rms","减速箱1振动1均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 1:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"JSX1ZD2_202_arv","减速箱1振动2整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"JSX1ZD2_202_std","减速箱1振动2标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"JSX1ZD2_202_rms","减速箱1振动2均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 2:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"JSX1DJZD_203_arv","减速箱1底脚振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"JSX1DJZD_203_std","减速箱1底脚振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"JSX1DJZD_203_rms","减速箱1底脚振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						default:break;
					}
				}else if(board==2){
					switch(it.first){
						case 0:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZQDLZZD_301_arv","主驱动轮左振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZQDLZZD_301_std","主驱动轮左振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"ZQDLZZD_301_rms","主驱动轮左振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 1:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZQDLYZD_302_arv","主驱动轮右振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZQDLYZD_302_std","主驱动轮右振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"ZQDLYZD_302_rms","主驱动轮右振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 2:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZJZZZD_303_arv","张紧轴左振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZJZZZD_303_std","张紧轴左振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"ZJZZZD_303_rms","张紧轴左振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						case 3:calc_feature("topic_vibration_feature_data",it.second,{
							{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZJZYZD_304_arv","张紧轴右振动整流平均值"}},
							{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZJZYZD_304_std","张紧轴右振动标准差"}},
							{AMCUtilityAlgDataAnalysis::MeanSquareCal<double>,{check_point_id,check_point_name,"ZJZYZD_304_rms","张紧轴右振动均方根值"}}
						},std::make_index_sequence<3>{});break;
						default:break;
					}
				}
			}else if(id==0x7377&&it.second.size()){
				switch(it.first){
					case 0:calc_feature("topic_record_feature_data",it.second,{
						{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"DJ1WD_401_avg","电机1温度平均值"}},
						{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"DJ1WD_401_std","电机1温度标准差"}},
					},std::make_index_sequence<3>{});break;
					case 1:calc_feature("topic_record_feature_data",it.second,{
						{AMCUtilityAlgDataAnalysis::AverageCal<double>,{"jsx2","jsx2","FSDXTTGL1WD_402_avg","扶手带系统托滚轮1温度平均值"}},
						{AMCUtilityAlgDataAnalysis::StdCal<double>,{"jsx2","jsx2","FSDXTTGL1WD_402_std","扶手带系统托滚轮1温度标准差"}},
					},std::make_index_sequence<3>{});break;
					case 2:calc_feature("topic_record_feature_data",it.second,{
						{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"FSDXTYJL1WD_403_avg","扶手带系统压紧轮1温度平均值"}},
						{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"FSDXTYJL1WD_403_std","扶手带系统压紧轮1温度标准差"}},
					},std::make_index_sequence<3>{});break;
					case 3:calc_feature("topic_record_feature_data",it.second,{
						{AMCUtilityAlgDataAnalysis::AverageCal<double>,{check_point_id,check_point_name,"ZJZZWY_404_avg","张紧轴左位移平均值"}},
						{AMCUtilityAlgDataAnalysis::StdCal<double>,{check_point_id,check_point_name,"ZJZZWY_404_std","张紧轴左位移标准差"}},
					},std::make_index_sequence<3>{});break;
					default:break;
				}
			}
		}
	}
}